﻿using DotNetDetour.DetourWays;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace DotNetDetour
{
    /*
      [UnmanagedFunctionPointer(CallingConvention.StdCall)]
      delegate int deltimeGetTime();
     */

    //public class ApiHook<TFunc> : IDisposable
    public class ApiHook<TFunc> : IDisposable where TFunc : Delegate
    {
        private HookInfo _hookInfo { get; set; }
        private TFunc _UserFunc;
        public TFunc OldFunc { get; private set; }

        public bool Hook(IntPtr rawFunc, TFunc newFunc)
        {
            _UserFunc = newFunc;
            IDetour engine = DetourFactory.CreateDetourEngine();
            _hookInfo = engine.Patch(rawFunc, Marshal.GetFunctionPointerForDelegate(newFunc), IntPtr.Zero);
            //OldFunc = Marshal.GetDelegateForFunctionPointer<TFunc>(_hookInfo.OldFunc);
            // 兼容 .NET 4.0 的非泛型方法
            OldFunc = (TFunc)Marshal.GetDelegateForFunctionPointer(_hookInfo.OldFunc, typeof(TFunc));
            return true;
        }

        public bool Hook(string dllName, string funcName, TFunc newFunc)
        {
            var h = NativeAPI.GetModuleHandle(dllName);
            if (h == IntPtr.Zero)
                h = NativeAPI.LoadLibrary(dllName);
            if (h == IntPtr.Zero) return false;

            var addr = NativeAPI.GetProcAddress(h, funcName);
            if (addr == IntPtr.Zero) return false;

            return Hook(addr, newFunc);
        }

        public void Dispose()
        {
            if (_hookInfo == null) return;

            IDetour engine = DetourFactory.CreateDetourEngine();
            engine.Unpatch(_hookInfo);
            _hookInfo = null;
            _UserFunc = default;
            GC.SuppressFinalize(this);
        }
    }
}